package com.sc.common.aspect;


import com.sc.common.annotations.EnableDistributedCaching;
import com.sc.common.annotations.EnableLocalCaching;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * 缓存拦截器，先查缓存再查数据库
 */
@Aspect
@Component
public class CacheAspect extends BaseCacheAspect {

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.selectByPrimaryKey(..))")
    private void selectByPrimaryKey(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.existsWithPrimaryKey(..))")
    private void existsWithPrimaryKey(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.selectOne(..))")
    private void selectOne(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.selectOneByExample(..))")
    private void selectOneByExample(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.insert(..))")
    private void insert(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.insertList(..))")
    private void insertList(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.updateByPrimaryKey(..))")
    private void updateByPrimaryKey(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.updateByPrimaryKeySelective(..))")
    private void updateByPrimaryKeySelective(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.updateByExample(..))")
    private void updateByExample(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.deleteByPrimaryKey(..))")
    private void deleteByPrimaryKey(){}

    @Pointcut("execution(* com.sc.common.mapper.IBaseMapper.deleteByExample(..))")
    private void deleteByExample(){}

    @Autowired
    private Environment environment;

    @Around("selectByPrimaryKey() || existsWithPrimaryKey() || selectOne() || selectOneByExample()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        Signature sig = jp.getSignature();
        if (sig instanceof MethodSignature) {
            Class proxyClass = getProxyClass(jp);
            Class returnClass = getGenericClass(proxyClass);

            // 是否开启本地缓存
            Object enableLocalCachingObj = returnClass.getAnnotation(EnableLocalCaching.class);

            // 是否开启分布式缓存
            Object enableDistributedCacheObj = returnClass.getAnnotation(EnableDistributedCaching.class);

            if(enableLocalCachingObj != null && enableDistributedCacheObj != null) {
                return super.around(jp,3);
            }else if(enableDistributedCacheObj != null){
                return super.around(jp,2);
            }else if(enableLocalCachingObj != null){
                return super.around(jp,1);
            }else{
                return jp.proceed();
            }
        }else{
            return jp.proceed();
        }
    }

    @AfterReturning("insert() || insertList() || updateByPrimaryKey() || updateByPrimaryKeySelective() || updateByExample() || deleteByPrimaryKey() || deleteByExample()")
    public void afterReturning(JoinPoint jp) throws Throwable {
        Signature sig = jp.getSignature();
        if (sig instanceof MethodSignature) {
            Class proxyClass = getProxyClass(jp);
            Class returnClass = getGenericClass(proxyClass);

            // 是否开启本地缓存
            Object enableLocalCachingObj = returnClass.getAnnotation(EnableLocalCaching.class);

            // 是否开启分布式缓存
            Object enableDistributedCacheObj = returnClass.getAnnotation(EnableDistributedCaching.class);

            if(enableLocalCachingObj != null && enableDistributedCacheObj != null) {
                super.afterReturning(jp,3);
            }else if(enableDistributedCacheObj != null){
                super.afterReturning(jp,2);
            }else if(enableLocalCachingObj != null){
                super.afterReturning(jp,1);
            }else{
                super.afterReturning(jp,0);
            }
        }
    }
}
